home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / comm2 / parnet.lha / parnet / sources / par.asm < prev    next >
Assembly Source File  |  1993-11-18  |  20KB  |  736 lines

  1.  
  2.         ;   PARALLEL PORT NETWORK LOW LEVEL ROUTINES
  3.         ;
  4.         ;   CABLE:  Connect D7-D0,SEL,POUT, and BUSY across,
  5.         ;        Connect ACK to SEL locally:
  6.         ;        Connect GND lines indicated
  7.         ;
  8.         ;   (2-9)   D7-D0   ------------    D7-D0
  9.         ;   (12)    POUT    ------------    POUT
  10.         ;   (11)    BUSY    ------------    BUSY       PARALLEL PORT
  11.         ;   (13)    SEL     --+------+--    SEL
  12.         ;   (10)    ACK     -/        \-    ACK
  13.         ;   (18-22) GND     ------------    GND
  14.         ;
  15.         ;   WARNING: you cannot connect RI on the serial port to your
  16.         ;         modem because it interferes with the parallel
  17.         ;         port's SEL line in this configuration.
  18.         ;
  19.         ;   *    28K/sec bandwidth
  20.         ;   *    # machines depends on extra hardware for buffering,
  21.         ;    but 3 ought to work fine without any extra hardware.
  22.         ;
  23.         ;    (network protocol can now handle 254)
  24.         ;
  25.         ;   Data Line Definitions:
  26.         ;    CIAA PORTB :    D7-D0    used for byte data transfer
  27.         ;    CIAB PORTA :    D2-D0    used for line aquisition and
  28.         ;                handshaking (SEL,POUT,BUSY)
  29.         ;
  30.         ;   All lines pulled up.  Thus, asserted state is a 0.    Idle
  31.         ;   state is an undriven (1).  Protocol transfers a byte at
  32.         ;   a time.  Protocol is ethernet style with a small window
  33.         ;   of error in the line aquisition routine.
  34.         ;
  35.         ;   Note:   Timeouts should be set around a second.  Ideally
  36.         ;        defaults should be fixed on faster machines.
  37.         ;
  38.         ;   CIAB PORTA    D0  ~ACK    hand shake
  39.         ;        D1  ~REQ    hand shake
  40.         ;        D2   CTL    1 = special byte, 0 = data byte.
  41.         ;                (for address mark, valid when ~REQ
  42.         ;                 goes low.    For EOP mark, sample
  43.         ;                 when ~REQ goes high)
  44.         ;
  45.         ;                PROTOCOL
  46.         ;
  47.         ;   HandShake    (Reader <- Writer transfer).  A Handshake
  48.         ;        sequence transfers TWO bytes of information.
  49.         ;
  50.         ;        WRITER                READER
  51.         ;    |-> place data, ~REQ->0
  52.         ;    |                 wait for ~REQ->0
  53.         ;    |                 read data & store
  54.         ;    |                 set ~ACK->0
  55.         ;    |   wait ~ACK->0
  56.         ;    |   place data, ~REQ->1
  57.         ;    |                 wait for ~REQ->1
  58.         ;    |                 read data & store
  59.         ;    |                 set ~ACK->1
  60.         ;    |   wait ~ACK->1
  61.         ;    |<- LOOP  (2 bytes written)      LOOP  (2 bytes read)
  62.         ;
  63.         ;
  64.         ;   Read:   (1) Determine if your machine is being addressed
  65.         ;        (~REQ=0, data=myaddress, CTL=1)
  66.         ;        (1) set DDR for ~ACK to output and
  67.         ;        (2) Handshake sequence for the address mark, only
  68.         ;        first byte valid.
  69.         ;        (3) Handshake sequence for data util rcv byte
  70.         ;        with CTL = 1 (EOP), byte must == 0.
  71.         ;        (4) Set ~ACK (bit 0) to input
  72.         ;
  73.         ;   Write:  (1) AQUIRE THE NETWORK (see below)
  74.         ;        involves gaining control and then setting the
  75.         ;        DDR for CTL and ~REQ to outputs.
  76.         ;
  77.         ;        Also checks if somebody is writing to us,
  78.         ;        in which case -2 is returned instantaniously
  79.         ;        indicating we should do a ParRead().
  80.         ;
  81.         ;        (2) Handshake sequence for address mark, send dest
  82.         ;        address (second byte garbage).  Note that CTL->1
  83.         ;        *BEFORE* we set ~REQ->0
  84.         ;        (3) Handshake sequence for data bytes
  85.         ;        (4) Handshake sequence for EOP mark (Note that CTL->1
  86.         ;        *AFTER* we get the ~ACK->1 and before release
  87.         ;        ~REQ (->1).  Only firstbyte valid and set to 0.
  88.         ;
  89.         ;        (5) Set ~ACK and ~CTL to inputs
  90.         ;
  91.         ;   AQUIRE: Line aquisition prevents two people from writing to
  92.         ;        the net at the same time.
  93.         ;
  94.         ;        * A line is considered aquired if ANY of the 3
  95.         ;          control lines is 0.
  96.         ;        * If network is not aquired:
  97.         ;        - set ~ACK to output and 1
  98.         ;        - bclr ~ACK to 0 and bne success
  99.         ;          (else set ~ACK to input and try again)
  100.         ;        - set data lines to output and place my address
  101.         ;          (Must ]be done before CTL is glitched)
  102.         ;        - set ~CTL to output and 1
  103.         ;        - set CTL to 0 and then 1 (glitch it) to cause
  104.         ;          FLAG interrupt on all other machines
  105.         ;        - set ~REQ to output and 0 (beginning of handshake
  106.         ;          sequence)
  107.         ;        - lastly, release ~ACK by setting it to an input
  108.         ;
  109.         ;          Note that at all times at least one line is a 0
  110.         ;          so no other machine will attempt to aquire the net.
  111.         ;
  112.         ;   Note that the destination address is placed on the data
  113.         ;   lines after we have aquired the line but before we glitch
  114.         ;   the CTL line to cause an interrupt.  This allows the
  115.         ;   other machines to instantaniously determine who is being
  116.         ;   addressed.
  117.         ;
  118.         ;   Note that the CTL line gets glitched at the end of a packet
  119.         ;   too for the EOP mark.  In this case there is a 0 on the
  120.         ;   data lines so while an interrupt is generated, nobody
  121.         ;   thinks they are being addressed.
  122.  
  123.         INCLUDE "exec/types.i"
  124.         INCLUDE "exec/execbase.i"
  125.  
  126.         XREF    _intena
  127.  
  128. DISABLE     MACRO
  129.         MOVE.W    #$04000,_intena     *(NOT IF_SETCLR)+IF_INTEN
  130.         ADDQ.B    #1,IDNestCnt(A6)
  131.         ENDM
  132.  
  133. ENABLE        MACRO
  134.         SUBQ.B    #1,IDNestCnt(A6)
  135.         BGE.S    ENABLE\@
  136.         MOVE.W    #$0C000,_intena     *IF_SETCLR+IF_INTEN
  137. ENABLE\@
  138.         ENDM
  139.  
  140.  
  141.         section __MERGED,DATA
  142.  
  143.         xdef    _ParLLTimeout
  144.         xdef    _ParDAT
  145.         xdef    _ParDDR
  146.         xdef    _ParCollision1
  147.         xdef    _ParCollision2
  148.         xref    _SysBase
  149.  
  150.         ;   Note, the timeout is set manually on init by using the
  151.         ;   timer.device to time one second.
  152.  
  153. _ParLLTimeout    dc.l    1000000     ; default timeout value (count). 1 second
  154. _ParDAT     dc.l    $BFE101     ; data port
  155. _ParDDR     dc.l    $BFE301     ; data ddr
  156. _ParCAT     dc.l    $BFD000     ; ctl  port (D0-D2)
  157. _ParCDR     dc.l    $BFD200     ; ctl  ddr  (D0-D2)
  158. _ParNetAddr    dc.b    0        ; default network address
  159. _DummyBuf    dc.b    0        ; dummy buffer
  160.         dc.b    0        ; dummy buffer
  161.         dc.b    0        ; pad
  162. _ParCollision1    dc.l    0        ; statistics
  163. _ParCollision2    dc.l    0        ;
  164. Null        dc.l    0        ; always 0
  165.         dc.l    0        ; always 0
  166.  
  167.     ifnd DEBUG
  168. DEBUG        set    0
  169.     endc
  170.     ifne DEBUG
  171.         xdef    _ParDebug
  172. _ParDebug    ds.l    16        ; 16 longword debug entries
  173.     endc
  174.  
  175.         section text,code
  176.  
  177.         ;   (void) ParAddress(myaddr)
  178.         ;    Set my address to (1-254)
  179.         ;
  180.         ;    0 and 255 are reserved!
  181.         ;
  182.         ;   int  = ParDataReady()
  183.         ;    returns 1  if packet pending
  184.         ;    returns 0  if line is currently idle
  185.         ;    returns -1 if packet isn't for you
  186.         ;
  187.         ;    if line has been aquired but no control address has been
  188.         ;    put on it yet, ParDataReady() will wait for a control
  189.         ;    address.  Thus, after a signal, a single call to
  190.         ;    ParDataReady() should suffice.
  191.         ;
  192.         ;   n = ParReadV (buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  193.         ;    (buffer sizes must be even)
  194.         ;   n = ParRead (buf, bytes)
  195.         ;    read a pending packet.    Returns n = -1 (1 second timeout
  196.         ;    no packet pending), n = 0 to bytes -1 (1 second timeout
  197.         ;    after transmission interrupted), n = bytes (success),
  198.         ;    or n > bytes (transmitting machine's packet was larger
  199.         ;    than we can handle, extra bytes thrown out)
  200.         ;
  201.         ;    NOTE: requesting an odd number of bytes is O.K. but
  202.         ;          if you request N where N is odd and the writer
  203.         ;          sends N + 1 you will never know (N will be
  204.         ;          returned).  See ParWrite() below
  205.         ;
  206.         ;   n = ParWriteV (destadr, buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  207.         ;    (buffer sizes must be even)
  208.         ;   n = ParWrite(destadr, buf, bytes)
  209.         ;    write a packet.  Returns:
  210.         ;    n = -2    Cannot write anything, a packet is pending
  211.         ;        (instantanious)
  212.         ;    n = -1    Destination machine does not respond (1 sec to)
  213.         ;    n = N    N bytes written ok (success if n == bytes)
  214.         ;
  215.         ;    NOTE: sending an odd number of bytes is O.K. but if
  216.         ;    you write N where N is odd and the reader requests
  217.         ;    N + 1 he will get N + 1 the last byte being garbage.
  218.         ;
  219.         ;
  220.         ;   CIAA PORTB    :  DATA ONLY
  221.         ;   CIAB PORTA    :  D0    ~DAck
  222.         ;           D1    ~DRdy
  223.         ;           D2    Ctl
  224.  
  225.         xdef    _ParRead
  226.         xdef    _ParReadV
  227.         xdef    _ParWrite
  228.         xdef    _ParWriteV
  229.         xdef    @ParAddress
  230.         xdef    _ParAddress
  231.         xdef    @ParDataReady
  232.         xdef    _ParDataReady
  233.         xdef    _LongCheckSum
  234.         xdef    @Time10000
  235.         xdef    _Time10000
  236.  
  237. _ParAddress:    move.l    4(sp),D0                ;   address 1-254
  238. @ParAddress:
  239.         move.b    D0,_ParNetAddr        ;   store
  240.         rts
  241.  
  242.         ;   ParDataReady()
  243.         ;
  244.         ;   -1    packet isn't for you
  245.         ;   0    line is idle
  246.         ;   1    packet probably pending for you
  247.  
  248. @ParDataReady:
  249. _ParDataReady:    move.l    _ParDAT,A0        ;   data register
  250.         move.l    _ParCAT,A1        ;   data control register
  251.  
  252. .pdstable    move.b    (A1),D0
  253.         move.b    (A0),D1
  254.         cmp.b    (A1),D0                 ;   control lines stable?
  255.         bne    .pdstable
  256.  
  257.         ;   Now, ParDataReady might be called after the sending machine
  258.         ;   has aquired but before it can assert REQ.  However, the
  259.         ;   sending machine has already (guarenteed) placed its address
  260.         ;   on the data port.  So while the address matches, loop while
  261.         ;   REQ not asserted.
  262.  
  263.         btst.l    #1,D0            ;   ~Req asserted?
  264.         beq    .pd10            ;   beq yes
  265.         cmp.b    _ParNetAddr,D1        ;   no, does data match anyway?
  266.         beq    .pdstable        ;   YES, loop until get ~REQ or
  267.         bra    .pdfail         ;   data bad.
  268.  
  269. .pd10        btst.l    #2,D0            ;   yes, Ctl ?
  270.         beq    .pdrn            ;   no, middle of some packet
  271.         cmp.b    _ParNetAddr,D1        ;   yes, my address?
  272.         bne    .pdrn
  273.         moveq.l #1,D0            ;   yes, packet (probably) for us
  274.         rts
  275.  
  276. .pdfail     btst.l    #2,D0            ;   fail due to ~Req not asserted
  277.         beq    .pdrn            ;   Ctl = 0, line busy
  278. .pdr0        moveq.l #0,D0            ;   line idle
  279.         rts
  280. .pdrn        moveq.l #-1,D0            ;   line busy, packet not for me
  281.         rts
  282.  
  283. _ParReadV:                    ;   Read Into Vector
  284.         movem.l D2-D7/A2-A5,-(sp)
  285.         lea    12+40(sp),A3
  286.         bra    .rm000
  287.  
  288. _ParRead:
  289.         movem.l D2-D7/A2-A5,-(sp)
  290.         lea    Null,A3         ;   Pointer to next vector
  291. .rm000        move.l    4+40(sp),A0             ;   A0 = buffer to read into
  292.         move.l    8+40(sp),D7             ;   D7 = # bytes to read (maximum)
  293.         move.l    _ParDAT,A1        ;   A1 = data reg
  294.         move.l    _ParDDR,A2        ;   A2 = ddr
  295.         move.l    _ParCAT,A4        ;   A4 = data reg
  296.         move.l    _ParCDR,A5        ;   A5 = ddr
  297.  
  298.         move.b    #0,(A2)                 ;   ensure all are inputs
  299.         bclr.b    #0,(A5)
  300.         bclr.b    #1,(A5)
  301.         bclr.b    #2,(A5)
  302.  
  303.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  304.         moveq.l #-1,D6            ;   D6 = # bytes read so far
  305.  
  306.         ;   WAIT LOOK FOR ADDRESS MARK
  307.         ;
  308.         ;   Ctl = 1, ~DReq = 0
  309.  
  310.         move.l    D5,D4            ;   D4 = timeout countdown
  311. .rmstab     move.b    (A4),D0                 ;   control data
  312.         move.b    (A1),D1                 ;   data data (network addr)
  313.         cmp.b    (A4),D0
  314.         bne    .rmstab
  315.         btst.l    #2,D0            ;   expect CTL = 1
  316.         beq    .rms1            ;   nope
  317.         btst.l    #1,D0            ;   expect ~REQ = 0
  318.         beq    .rms2            ;   yes
  319. .rms1
  320.     ifne DEBUG
  321.         add.l    #1,_ParDebug+0
  322.     endc
  323.         subq.l    #1,D4            ;   timeout
  324.         bne    .rmstab
  325.         bra    .rmend            ;   no address mark!
  326.  
  327. .rms2        cmp.b    _ParNetAddr,D1        ;   my address?
  328.         bne    .rms1            ;   no, timeout loop
  329.  
  330.         ;   My address, ~Ack byte.
  331.  
  332.         bclr.b    #0,(A4)                 ;   set ~ACK to 0
  333.         bset.b    #0,(A5)                 ;   set to output
  334.  
  335.         move.l    D5,D4            ;   reset timeout
  336. .rms4        btst.b    #1,(A4)                 ;   wait for ~REQ to go away
  337.         bne    .rms5
  338.     ifne DEBUG
  339.         add.l    #1,_ParDebug+4
  340.     endc
  341.         subq.l    #1,D4
  342.         bne    .rms4
  343.         moveq.l #-2,D6            ;   ~REQ not released ?????
  344.         bra    .rmend
  345.  
  346. .rms5        bset.b    #0,(A4)                 ;   release ~ACK
  347.         moveq.l #0,D6            ;   set # bytes read to 0
  348.         bra    .rms10            ;   skip past move
  349.  
  350.         ;   MAIN READ LOOP
  351.         ;
  352.         ;   D6 holds cnt, A0 buffer ptr, D0-D4 free to allocate
  353.  
  354. .rms10loop
  355.         move.b    D0,(A0)                 ;   store data
  356.         addq.l    #1,A0            ;   next addr.
  357.  
  358. .rms10        btst.b    #1,(A4)                 ;   wait for ~REQ asserted
  359.         beq    .rms20
  360.         btst.b    #1,(A4)
  361.         beq    .rms20
  362.         move.l    D5,D4            ;   load timeout
  363. .rms11        btst.b    #1,(A4)                 ;   wait for ~REQ asserted w/to
  364.         beq    .rms20
  365.     ifne DEBUG
  366.         add.l    #1,_ParDebug+8
  367.     endc
  368.         subq.l    #1,D4
  369.         bne    .rms11
  370.         bra    .rmend
  371.  
  372. .rms20        move.b    (A1),D0                 ;   get data and
  373.         bclr.b    #0,(A4)                 ;   assert ~ACK
  374.  
  375.         ;   note, on CTL = 1 end sequence this data item is a dummy
  376.  
  377.         move.b    D0,(A0)                 ;   store data
  378.         addq.l    #1,A0            ;   next addr.
  379.         addq.l    #2,D6            ;   optimized but not quite
  380.                         ;   true, we've only written 1 sf.
  381.         btst.b    #1,(A4)                 ;   wait for ~REQ released
  382.         bne    .rms30
  383.         btst.b    #1,(A4)
  384.         bne    .rms30
  385.         move.l    D5,D4
  386. .rms21        btst.b    #1,(A4)                 ;   wait for ~REQ rel w/ to
  387.         bne    .rms30
  388.     ifne DEBUG
  389.         add.l    #1,_ParDebug+12
  390.     endc
  391.         subq.l    #1,D4
  392.         bne    .rms21
  393.         bra    .rmendsub        ;   sub because D6 is 2 ahead
  394.  
  395. .rms30        move.b    (A1),D0                 ;   get data
  396.         move.b    (A4),D1                 ;   get CTL status
  397.         bset.b    #0,(A4)                 ;   release ~ACK
  398.         btst.l    #2,D1            ;   EOP if CTL = 1
  399.         bne    .rmeop
  400.  
  401.         ;   CANNOT STORE DATA HERE!  In case odd # bytes requested,
  402.         ;   second byte would overflow buffer
  403.  
  404.         subq.l    #2,D7            ;   # bytes remaining
  405.         bgt    .rms10loop
  406.         bne    .rmnlb
  407.         move.b    D0,(A0)                 ;   if D7 = 0 its even and we
  408.                         ;   should store the last byte
  409. .rmnlb        cmp.l    #-1,D7            ;   -1 = was odd #
  410.         bne    .rmeven         ;   fixup count
  411.         subq.l    #1,D6
  412.  
  413. .rmeven
  414. .rmsev0     tst.l    (A3)                    ;   if next buffer NULL
  415.         beq    .rmovflow
  416.         move.l    (A3)+,A0                ;   next buffer
  417.         move.l    (A3)+,D7
  418.         beq    .rmsev0         ;   0 bytes, goto next buffer
  419.         bra    .rms10            ;   loop, continue reading
  420.  
  421. .rmovflow
  422.         lea    _DummyBuf,A0        ;   overflow, dummy buffer
  423.         bra    .rms10
  424.  
  425. .rmeop        tst.b    D0            ;   EOP data better be 0!
  426.         beq    .rmendsub
  427.         moveq.l #-3,D6
  428.         bra    .rmend
  429.  
  430. .rmendsub    subq.l    #2,D6            ;   because we were two ahead
  431.  
  432. .rmend        bset.b    #0,(A4)                 ;   active pull up before (?)
  433.         bclr.b    #0,(A5)                 ;   setting ~ACK to input
  434.         move.l    D6,D0            ;   return value
  435.         movem.l (sp)+,D2-D7/A2-A5       ;   restore registers
  436.         rts
  437.  
  438. _ParWriteV:    movem.l D2-D7/A2-A6,-(sp)       ;   write vector
  439.         lea    16+44(sp),A3
  440.         bra    .wm000
  441.  
  442. _ParWrite:
  443.         movem.l D2-D7/A2-A6,-(sp)
  444.         lea    Null,A3
  445. .wm000        move.l    4+44(sp),D3             ;   D3 = destination address
  446.         move.l    8+44(sp),A0             ;   A0 = buffer to write
  447.         move.l    12+44(sp),D7            ;   D7 = # bytes to write
  448.         move.l    _ParDAT,A1        ;   A1 = data reg
  449.         move.l    _ParDDR,A2        ;   A2 = ddr
  450.         move.l    _ParCAT,A4        ;   A4 = data reg
  451.         move.l    _ParCDR,A5        ;   A5 = ddr
  452. ;        move.l    4,A6            ;   SYSBase
  453.         move.l    _SysBase,A6        ;   SYSBase
  454.  
  455.         move.b    #0,(A2)
  456.         and.b    #%11111000,(A5)
  457.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  458.  
  459.         move.l    D5,D4            ;   D4 = timeout countdown
  460.         moveq.l #-2,D6            ;   D6 = # bytes written
  461.  
  462.         ;   AQUIRE THE LINE USING ~ACK
  463.  
  464. .wmstab
  465.         bset.b    #0,(A4)                 ;   so is a 1 when we set it to w
  466.  
  467.         DISABLE
  468.  
  469.         move.b    (A4),D0                 ;   get stable data
  470.         move.b    (A1),D1
  471.         cmp.b    (A4),D0
  472.         beq    .wmstab1
  473.  
  474.         ENABLE
  475.  
  476.         bra    .wmstab
  477.  
  478.         ;   Ints still disabled
  479.         ;   D0 holds ~ACK ~REQ CTL status
  480.  
  481. .wmstab1    and.b    #%111,D0        ;   ~ACK=1, ~REQ=1, CTL=1
  482.         cmp.b    #%111,D0
  483.         beq    .wm02
  484.  
  485.         ;   no, if CTL = 1, ~REQ = 0, and D1 = my address then
  486.         ;   return w/ -2
  487.  
  488.         btst.l    #1,D0
  489.         bne    .wm01
  490.         btst.l    #2,D0
  491.         beq    .wm01
  492.         cmp.b    _ParNetAddr,D1        ;   somebody calling me?
  493.         bne    .wm01
  494.  
  495.         ENABLE
  496.         bra    .wmend
  497.  
  498. .wm01
  499.         ENABLE
  500.  
  501.     ifne DEBUG
  502.         add.l    #1,_ParDebug+16
  503.     endc
  504.         subq.l    #1,D4
  505.         bne    .wmstab
  506.         bra    .wmend
  507.  
  508.         ;   interrupts still disabled
  509.         ;   we almost own the line
  510.  
  511. .wm02        bset.b    #0,(A5)                 ;   set ~ACK to an output
  512.         nop
  513.         bclr.b    #0,(A4)                 ;   assert ~ACK
  514.         bne    .wm05            ;   was released before, have line!
  515.  
  516.                         ;   don't have line,
  517.         bclr.b    #0,(A5)                 ;   set back to input
  518.         bra    .wm01
  519.  
  520.         ;   Line now aquired.
  521.  
  522. .wm05
  523.         ENABLE
  524.  
  525.         move.b    #$FF,(A2)               ;   set data ddr to outputs
  526.         move.b    D3,(A1)                 ;   set data lines to our addr
  527.  
  528.         ;   Before asserting ~REQ pulse CTL to cause interrupt on remote
  529.         ;   machines.  Note that our address is already on the data
  530.         ;   lines.
  531.  
  532.         bset.b    #2,(A5)                 ;   set CTL to output
  533.         bclr.b    #2,(A4)                 ;   pulse CTL to cause FLAG int
  534.         or.b    #%00000111,(A4)         ;   set CTL = 1 and make sure
  535.                         ;   REQ will be one when we
  536.         bset.b    #1,(A5)                 ;   set ~REQ to output
  537.  
  538.         bclr.b    #1,(A4)                 ;   assert ~REQ
  539.  
  540.         bclr.b    #0,(A5)                 ;   make ~ACK an input
  541.                         ;   (note that REQ->0 before ACK->release)
  542.  
  543.         moveq.l #-1,D6            ;   D6 = # bytes written
  544.  
  545.         ;   INTERRUPTS ENABLED FOR TXFER (fully handshaked)
  546.         ;
  547.         ;   Address mark ~ACK, wait for ~ACK asserted
  548.  
  549. .wm10        btst.b    #0,(A4)
  550.         beq    .wm15
  551.         move.l    D5,D4            ;   D4 = timeout countdown
  552. .wm11        btst.b    #0,(A4)
  553.         beq    .wm15
  554.     ifne DEBUG
  555.         add.l    #1,_ParDebug+20
  556.     endc
  557.         subq.l    #1,D4
  558.         bne    .wm11
  559.         bra    .wmend
  560.  
  561.         ;   got ack, now set CTL = 0 (leaves at least one line 0 so
  562.         ;   nobody else thinks the bus is idle!)
  563.         ;
  564.         ;   note:   Since this is the address mark, and is sampled by
  565.         ;        the reader before it asserts ~ACK, I can set CTL
  566.         ;        = 0 now instead of waiting till after ~ACK is
  567.         ;        released.
  568.  
  569. .wm15        bclr.b    #2,(A4)                 ;   set CTL = 0 for duration of pkt
  570.         nop                ;   ???
  571.         bset.b    #1,(A4)                 ;   release ~REQ
  572.  
  573.  
  574.         moveq.l #0,D6            ;   # bytes written
  575.  
  576.         ;   DATA XFER LOOP
  577.         ;
  578.         ;   wait for ~ACK to be released (->1).  If no more bytes
  579.         ;   then skip to .wm50
  580.  
  581. .wm20
  582.         tst.l    D7            ;   more data in this buffer?
  583.         ble    .wm50            ;   nope.
  584.  
  585.         btst.b    #0,(A4)                 ;   wait ~ACK released
  586.         bne    .wm30
  587.         move.l    D5,D4            ;   D4 = timeout countdown
  588. .wm21        btst.b    #0,(A4)
  589.         bne    .wm30            ;   need the timeout here?
  590.         btst.b    #0,(A4)
  591.         bne    .wm30
  592.     ifne DEBUG
  593.         add.l    #1,_ParDebug+24
  594.     endc
  595.         subq.l    #1,D4
  596.         bne    .wm21
  597.         bra    .wmend
  598.  
  599.         ;   Assert ~REQ for this data byte and wait for ~ACK
  600.  
  601. .wm30
  602.         move.b    (A0)+,D0                ;   get next data byte
  603.         move.b    D0,(A1)                 ;   store data and
  604.         bclr.b    #1,(A4)                 ;   assert ~REQ
  605.  
  606.         move.b    (A0)+,D0                ;   get next data byte
  607.         subq.l    #2,D7            ;   one less byte (this and next)
  608.         addq.l    #1,D6            ;   # bytes written (this only)
  609.                         ;   (not valid until we get ACK
  610.                         ;    which is why the wmendsub
  611.  
  612.         btst.b    #0,(A4)                 ;   wait for ACK
  613.         beq    .wm40
  614.         btst.b    #0,(A4)
  615.         beq    .wm40
  616.         move.l    D5,D4            ;   D4 = timeout countdown
  617. .wm31        btst.b    #0,(A4)
  618.         beq    .wm40
  619.     ifne DEBUG
  620.         add.l    #1,_ParDebug+28
  621.     endc
  622.         subq.l    #1,D4
  623.         bne    .wm31
  624.         bra    .wmendsub
  625.  
  626.         ;   Have ~ACK, byte transmitted.  ++bytes written, --bytes left
  627.         ;   and loop
  628.  
  629. .wm40        move.b    D0,(A1)                 ; store second byte
  630.         bset.b    #1,(A4)                 ; release ~REQ
  631.  
  632.         addq.l    #1,D6            ; # bytes written
  633.  
  634.         bra    .wm20
  635.  
  636.         ;   Last byte in buffer has been transmitted.
  637.         ;
  638.         ;   Get next buffer in vector
  639.  
  640. .wm50        tst.l    (A3)
  641.         beq    .wm50a
  642.         move.l    (A3)+,A0                ;   buffer ptr
  643.         move.l    (A3)+,D7                ;   # bytes
  644.         bra    .wm20            ;   loop to top
  645.  
  646. .wm50a
  647.         ;   Last byte has been transmitted,
  648.         ;
  649.         ;   Wait for ~ACK to be released and then assert ~REQ with
  650.         ;   EOP & CTL = 1
  651.         ;
  652.         ;   (timing on read is that CTL is sampled when ~REQ is
  653.         ;   RELEASED so no timing window here)
  654.  
  655.         btst.b    #0,(A4)                 ;   Wait ~ACK released
  656.         beq    .wm50
  657.  
  658.         move.b    #0,(A1)                 ;   EOP mark (0)
  659.         bclr.b    #1,(A4)                 ;   assert ~REQ
  660.  
  661.         ;   Wait for ~ACK asserted
  662.  
  663.         btst.b    #0,(A4)
  664.         beq    .wm60
  665.         move.l    D5,D4
  666. .wm51        btst.b    #0,(A4)
  667.         beq    .wm60
  668.     ifne DEBUG
  669.         add.l    #1,_ParDebug+32
  670.     endc
  671.         subq.l    #1,D4
  672.         bne    .wm51
  673.         moveq.l #-3,D6            ;   EOP failed
  674.         bra    .wmend
  675.  
  676.         ;   Set CTL = 1 then release ~REQ, then wait for ~ACK released
  677.  
  678. .wm60        or.b    #%00000100,(A4) ;   set CTL = 1
  679.         or.b    #%00000110,(A4) ;   release ~REQ
  680.  
  681.         ;   Wait ~ACK released ?
  682.  
  683. .wm61        btst.b    #0,(A4)
  684.         beq    .wm61
  685.  
  686.         ;   Add D7 to D6.  This handles fixup if an odd number of bytes
  687.         ;   were requested written, D7 will be -1 (odd) or 0 (even) and
  688.         ;   D6 will be one too large (odd) or perfect (even)
  689.  
  690.         add.l    D7,D6
  691.  
  692.         bra    .wmend
  693.  
  694. .wmendsub    subq.l    #1,D6        ;   was ahead in count
  695.  
  696. .wmend        move.b    #0,(A2)         ;   set data port to input
  697.         and.b    #%11111000,(A5) ;   set data port for ctl lines to input
  698.  
  699.         move.l    D6,D0            ;   return value
  700.         movem.l (sp)+,D2-D7/A2-A6       ;   restore registers
  701.         rts
  702.  
  703.         ;   sum = LongCheckSum(buf, bytes)
  704.         ;   (buffer must be lw aligned and bytes must be multiples of 4)
  705.  
  706. _LongCheckSum:
  707.         moveq.l #0,D0            ;   D0 = accumulated checksum
  708.         move.l    4(sp),A0                ;   A0 = ptr
  709.         move.l    8(sp),D1                ;   D1 = bytes
  710.         beq    .pcrts
  711. .pc10        add.l    (A0)+,D0
  712.         subq.l    #4,D1
  713.         bgt    .pc10
  714.         tst.l    D1
  715.         bne    .pc20            ;   not multiple of 4 bytes!
  716. .pcrts        rts                ;   return checksum
  717. .pc20        illegal             ;   cause task-held msg
  718.         rts
  719.  
  720.         ;   Delays 10000 rough timeout loops, used to determine
  721.         ;   timeout on init
  722.  
  723. @Time10000:
  724. _Time10000:
  725.         move.l    #10000,D4
  726. t10        move.l    D4,D4
  727.         move.l    D4,D4
  728.         move.l    D4,D4
  729.         move.l    D4,D4
  730.         subq.l    #1,D4
  731.         bne    t10
  732.         rts
  733.  
  734.         END
  735.  
  736.